﻿using DeviceDetectorNET.Cache;
using Framework.Core.Attributes;
using Framework.Core.Consts;
using Framework.Core.Enums;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using my.abp.Domain.IManagers.Org;
using my.abp.Domain.IManagers.Role;
using my.abp.Domain.IManagers.User;
using my.abp.Domain.Managers.User;
using my.abp.Domain.Repositories;
using my.abp.Domain.Repositories.User;
using my.abp.Domain.Shared.Entities;
using my.abp.Domain.Shared.Enums;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Caching;
using Volo.Abp.Domain.Services;
using Framework.Core.Extensions;
using Mapster;
using Volo.Abp.Uow;
using my.abp.Domain.Repositories.Org;
using Framework.Core.Extensions;
using Microsoft.Extensions.Caching.Distributed;
using System.Net;
using Framework.Caching.FreeRedis;

namespace my.abp.Domain.Managers.Org
{
	public class SysOrgManager : DomainService, ISysOrgManager
	{
		private readonly ISysOrgRepository _sysOrgRepository;
		private readonly ISysUserExtOrgManager _sysUserExtOrgManager;
		private readonly ISysUserRoleManager _sysUserRoleManager;
		private readonly ISysRoleOrgManager _sysRoleOrgManager;
		private Framework.AspNetCore.User.CurrentUser _CurrentUser;
		private readonly IWantDistributedCache _sysCache;
		
		public SysOrgManager(ISysUserExtOrgManager sysUserExtOrgManager, IWantDistributedCache sysCache,
			ISysUserRoleManager sysUserRoleManager, ISysRoleOrgManager sysRoleOrgManager,
			ISysOrgRepository sysOrgRepository, Framework.AspNetCore.User.CurrentUser CurrentUser)
		{
			_sysOrgRepository = sysOrgRepository;
			_CurrentUser = CurrentUser;
			_sysCache = sysCache;
			_sysUserExtOrgManager = sysUserExtOrgManager;
			_sysUserRoleManager = sysUserRoleManager;
			_sysRoleOrgManager = sysRoleOrgManager;
		}

		/// <summary>
		/// 获取机构
		/// </summary>
		/// <returns></returns>
		public async Task<SysOrg> GetOrg()
		{
			return await _sysOrgRepository.GetFirstAsync(u => u.Id == _CurrentUser.OrgId);
		}

		/// <summary>
		/// 获取机构列表
		/// </summary>
		/// <param name="Id"></param>
		/// <param name="Name"></param>
		/// <param name="Code"></param>
		/// <returns></returns>
		public async Task<List<SysOrg>> GetList(long Id,string Name,string Code)
		{

			// 获取拥有的机构Id集合
			var userOrgIdList = await GetUserOrgIdList();

			var queryable = await _sysOrgRepository.AsQueryable();
			var iSugarQueryable = queryable.OrderBy(u => u.OrderNo);

			// 带条件筛选时返回列表数据
			if (!string.IsNullOrWhiteSpace(Name) || !string.IsNullOrWhiteSpace(Code))
			{
				return await iSugarQueryable.WhereIF(userOrgIdList.Count > 0, u => userOrgIdList.Contains(u.Id))
					.WhereIF(!string.IsNullOrWhiteSpace(Name), u => u.Name.Contains(Name))
					.WhereIF(!string.IsNullOrWhiteSpace(Code), u => u.Code == Code)
					.ToListAsync();
			}

			var sysOrg = await _sysOrgRepository.GetSingleAsync(u => u.Id == Id);
			var orgTree = new List<SysOrg>();
			if (_CurrentUser.SuperAdmin)
			{
				orgTree = await iSugarQueryable.ToTreeAsync(u => u.Children, u => u.Pid, sysOrg?.Pid);
			}
			else
			{
				orgTree = await iSugarQueryable.ToTreeAsync(u => u.Children, u => u.Pid, sysOrg?.Pid, userOrgIdList.Select(d => (object)d).ToArray());
				// 递归禁用没权限的机构（防止用户修改或创建无权的机构和用户）
				HandlerOrgTree(orgTree, userOrgIdList);
			}
			return orgTree;
		}

		/// <summary>
		/// 根据用户Id获取机构Id集合
		/// </summary>
		/// <returns></returns>
		public async Task<List<long>> GetUserOrgIdList()
		{
			if (_CurrentUser.SuperAdmin)
				return new List<long>();
			
			var userId = _CurrentUser.UserId;
			var orgIdList = _sysCache.Get<List<long>,string>($"{CacheConst.KeyUserOrg}{userId}",CacheConst.cacheName); // 取缓存
			if (orgIdList == null || orgIdList.Count < 1)
			{
				// 扩展机构集合
				var orgList1 = await _sysUserExtOrgManager.GetUserExtOrgList(userId);
				// 角色机构集合
				var orgList2 = await GetUserRoleOrgIdList(userId);
				// 机构并集
				orgIdList = orgList1.Union(orgList2).ToList();
				// 当前所属机构
				if (!orgIdList.Contains(_CurrentUser.OrgId))
					orgIdList.Add(_CurrentUser.OrgId);
				_sysCache.Set<List<long>, string>($"{CacheConst.KeyUserOrg}{userId}", orgIdList, CacheConst.cacheName); // 存缓存
			}
			return orgIdList;
		}

		/// <summary>
		/// 获取用户角色机构Id集合
		/// </summary>
		/// <param name="userId"></param>
		/// <returns></returns>
		private async Task<List<long>> GetUserRoleOrgIdList(long userId)
		{
			var roleList = await _sysUserRoleManager.GetUserRoleList(userId);
			if (roleList.Count < 1)
				return new List<long>(); // 空机构Id集合

			return await GetUserOrgIdList(roleList);
		}

		/// <summary>
		/// 根据角色Id集合获取机构Id集合
		/// </summary>
		/// <param name="roleList"></param>
		/// <returns></returns>
		private async Task<List<long>> GetUserOrgIdList(List<SysRole> roleList)
		{
			// 按最大范围策略设定(若同时拥有ALL和SELF权限，则结果ALL)
			int strongerDataScopeType = (int)DataScopeEnum.Self;

			// 角色集合拥有的数据范围
			var customDataScopeRoleIdList = new List<long>();
			if (roleList != null && roleList.Count > 0)
			{
				roleList.ForEach(u =>
				{
					if (u.DataScope == DataScopeEnum.Define)
					{
						customDataScopeRoleIdList.Add(u.Id);
						strongerDataScopeType = (int)u.DataScope; // 自定义数据权限时也要更新最大范围
					}
					else if ((int)u.DataScope <= strongerDataScopeType)
						strongerDataScopeType = (int)u.DataScope;
				});
			}

			// 根据角色集合获取机构集合
			var orgIdList1 = await _sysRoleOrgManager.GetRoleOrgIdList(customDataScopeRoleIdList);
			// 根据数据范围获取机构集合
			var orgIdList2 = await GetOrgIdListByDataScope(strongerDataScopeType);

			// 缓存当前用户最大角色数据范围
			_sysCache.Set<dynamic, string>(CacheConst.KeyRoleMaxDataScope + _CurrentUser.UserId, strongerDataScopeType,CacheConst.cacheName);

			// 并集机构集合
			return orgIdList1.Union(orgIdList2).ToList();
		}

		/// <summary>
		/// 根据数据范围获取机构Id集合
		/// </summary>
		/// <param name="dataScope"></param>
		/// <returns></returns>
		private async Task<List<long>> GetOrgIdListByDataScope(int dataScope)
		{
			var orgId = _CurrentUser.OrgId;
			var orgIdList = new List<long>();
			// 若数据范围是全部，则获取所有机构Id集合
			if (dataScope == (int)DataScopeEnum.All)
			{
				var queryable = await _sysOrgRepository.AsQueryable();
				orgIdList = await queryable.Select(u => u.Id).ToListAsync();
			}
			// 若数据范围是本部门及以下，则获取本节点和子节点集合
			else if (dataScope == (int)DataScopeEnum.DeptChild)
			{
				orgIdList = await GetChildIdListWithSelfById(orgId);
			}
			// 若数据范围是本部门不含子节点，则直接返回本部门
			else if (dataScope == (int)DataScopeEnum.Dept)
			{
				orgIdList.Add(orgId);
			}
			return orgIdList;
		}

		/// <summary>
		/// 根据节点Id获取子节点Id集合(包含自己)
		/// </summary>
		/// <param name="pid"></param>
		/// <returns></returns>
		public async Task<List<long>> GetChildIdListWithSelfById(long pid)
		{
			var queryable = await _sysOrgRepository.AsQueryable();
			var orgTreeList = await queryable.ToChildListAsync(u => u.Pid, pid, true);
			return orgTreeList.Select(u => u.Id).ToList();
		}

		/// <summary>
		/// 递归禁用没权限的机构
		/// </summary>
		/// <param name="orgTree"></param>
		/// <param name="userOrgIdList"></param>
		private void HandlerOrgTree(List<SysOrg> orgTree, List<long> userOrgIdList)
		{
			foreach (var org in orgTree)
			{
				org.Disabled = !userOrgIdList.Contains(org.Id); // 设置禁用/不可选择
				if (org.Children != null)
					HandlerOrgTree(org.Children, userOrgIdList);
			}
		}

		/// <summary>
		/// 增加机构
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		public async Task<long> AddOrg(SysOrg input)
		{
			if (await _sysOrgRepository.IsAnyAsync(u => u.Name == input.Name && u.Code == input.Code))
				throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D2002));
			if (!_CurrentUser.SuperAdmin && input.Pid != 0)
			{
				// 新增机构父Id不是0，则进行权限校验
				var orgIdList = await GetUserOrgIdList();
				// 新增机构的父机构不在自己的数据范围内
				if (orgIdList.Count < 1 || !orgIdList.Contains(input.Pid))
					throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D2003));
			}

			// 删除与此父机构有关的用户机构缓存
			var pOrg = await _sysOrgRepository.GetFirstAsync(u => u.Id == input.Pid);
			if (pOrg != null)
				await DeleteUserOrgCache(pOrg.Id, pOrg.Pid);

			var insertable = await _sysOrgRepository.AsInsertable(input);
			var newOrg = await insertable.ExecuteReturnEntityAsync();
			return newOrg.Id;
		}

		/// <summary>
		/// 删除与此机构、父机构有关的用户机构缓存
		/// </summary>
		/// <param name="orgId"></param>
		/// <param name="orgPid"></param>
		private async Task DeleteUserOrgCache(long orgId, long orgPid)
		{
			return;
			//var userOrgKeyList = _sysCache.Get<List<string>,string>(CacheConst.KeyUserOrg,CacheConst.cacheName);
			//if (userOrgKeyList != null && userOrgKeyList.Count > 0)
			//{
			//	foreach (var userOrgKey in userOrgKeyList)
			//	{
			//		var userOrgs = _sysCache.Get<List<string>, string>(userOrgKey, CacheConst.cacheName);
			//		if (userOrgs.Contains(orgId) || userOrgs.Contains(orgPid))
			//		{
			//			var userId = long.Parse(userOrgKey.Substring(CacheConst.KeyUserOrg));

			//			var db = await _sysOrgRepository.GetDbContextAsync();
			//			var ContextID = db.ContextID;

			//			// 删除用户机构缓存
			//			_CacheOrgIdList.Remove($"{CacheConst.KeyUserOrg}{userId}");
			//			_CacheOrgIdList.Remove($"{CacheConst.KeyRoleMaxDataScope}{userId}");
			//			_CacheOrgIdList.Remove($"db:{ContextID}:orgList:{userId}");
			//		}
			//	}
			//}
		}

		/// <summary>
		/// 更新机构
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		/// <exception cref="UserFriendlyException"></exception>
		[UnitOfWork]
		public async Task UpdateOrg(SysOrg input)
		{
			if (input.Pid != 0)
			{
				//var pOrg = await _sysOrgRep.GetFirstAsync(u => u.Id == input.Pid);
				//_ = pOrg ?? throw Oops.Oh(ErrorCodeEnum.D2000);

				// 若父机构发生变化则清空用户机构缓存
				var sysOrg = await _sysOrgRepository.GetFirstAsync(u => u.Id == input.Id);
				if (sysOrg != null && sysOrg.Pid != input.Pid)
				{
					// 删除与此机构、新父机构有关的用户机构缓存
					DeleteUserOrgCache(sysOrg.Id, input.Pid);
				}
			}
			if (input.Id == input.Pid)
				throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D2001));

			if (await _sysOrgRepository.IsAnyAsync(u => u.Name == input.Name && u.Code == input.Code && u.Id != input.Id))
				throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D2002));

			// 父Id不能为自己的子节点
			var childIdList = await GetChildIdListWithSelfById(input.Id);
			if (childIdList.Contains(input.Pid))
				throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D2001));

			// 是否有权限操作此机构
			if (!_CurrentUser.SuperAdmin)
			{
				var orgIdList = await GetUserOrgIdList();
				if (orgIdList.Count < 1 || !orgIdList.Contains(input.Id))
					throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D2003));
			}

			var updateable = await _sysOrgRepository.AsUpdateable(input.Adapt<SysOrg>());
			await updateable.IgnoreColumns(true).ExecuteCommandAsync();
		}

		/// <summary>
		/// 删除机构
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		[UnitOfWork]
		public async Task DeleteOrg(SysOrg input)
		{
			var sysOrg = await _sysOrgRepository.GetFirstAsync(u => u.Id == input.Id) ??
				throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D1002));

			// 是否有权限操作此机构
			if (!_CurrentUser.SuperAdmin)
			{
				var orgIdList = await GetUserOrgIdList();
				if (orgIdList.Count < 1 || !orgIdList.Contains(sysOrg.Id))
					throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D2003));
			}

			//// 若机构为租户默认机构禁止删除
			//var isTenantOrg = await _sysOrgRep.ChangeRepository<SqlSugarRepository<SysTenant>>()
			//	.IsAnyAsync(u => u.OrgId == input.Id);
			//if (isTenantOrg)
			//	throw Oops.Oh(ErrorCodeEnum.D2008);

			//// 若机构有用户则禁止删除
			//var orgHasEmp = await _sysOrgRep.ChangeRepository<SqlSugarRepository<SysUser>>()
			//	.IsAnyAsync(u => u.OrgId == input.Id);
			//if (orgHasEmp)
			//	throw Oops.Oh(ErrorCodeEnum.D2004);

			// 若扩展机构有用户则禁止删除
			var hasExtOrgEmp = await _sysUserExtOrgManager.HasUserOrg(sysOrg.Id);
			if (hasExtOrgEmp)
				throw new UserFriendlyException(RemarkAttribute.GetEnumRemark(ErrorCodeEnum.D2005));

			// 若子机构有用户则禁止删除
			var queryable = await _sysOrgRepository.AsQueryable();
			var childOrgTreeList = await queryable.ToChildListAsync(u => u.Pid, input.Id, true);
			var childOrgIdList = childOrgTreeList.Select(u => u.Id).ToList();

			//// 若子机构有用户则禁止删除
			//var cOrgHasEmp = await _sysOrgRep.ChangeRepository<SqlSugarRepository<SysUser>>()
			//	.IsAnyAsync(u => childOrgIdList.Contains(u.OrgId));
			//if (cOrgHasEmp)
			//	throw Oops.Oh(ErrorCodeEnum.D2007);

			// 删除与此机构、父机构有关的用户机构缓存
			DeleteUserOrgCache(sysOrg.Id, sysOrg.Pid);

			// 级联删除机构子节点
			await _sysOrgRepository.DeleteAsync(u => childOrgIdList.Contains(u.Id));

			//// 级联删除角色机构数据
			//await _sysRoleOrgService.DeleteRoleOrgByOrgIdList(childOrgIdList);

			// 级联删除用户机构数据
			await _sysUserExtOrgManager.DeleteUserExtOrgByOrgIdList(childOrgIdList);
		}
	}
}
